package com.leeon.thread;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import static net.mindview.util.Print.print;

class Toast{
	public enum Status{
		DRY,BUTTERED,JAMMED
	}
	private Status status = Status.DRY;
	private final int id;
	public Toast(int id) {
		this.id = id;
	}
	public void buffer() {
		status = Status.BUTTERED;
	}
	public void jam() {
		status = Status.JAMMED;
	}
	public Status getStatus() {
		return status;
	}
	public int getID() {
		return id;
	}
	@Override
	public String toString() {
		return "Toash " + id + ": " + status;
	}
}

class ToastQueue extends LinkedBlockingDeque<Toast>{}

class Toaster implements Runnable{

	private ToastQueue toastQueue;
	private int count = 0;
	private Random rand = new Random(47);
	public Toaster(ToastQueue tq) {
		toastQueue = tq;
	}
	
	@Override
	public void run() {
		try {
			while(!Thread.interrupted()) {
				TimeUnit.MILLISECONDS.sleep(100 + rand.nextInt(500));
				Toast t = new Toast(count++);
				print(t);
				toastQueue.put(t);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		print("Toaster off");
	}
	
}

class Butterer implements Runnable{

	private ToastQueue dryQueue;
	private ToastQueue butteredQueue;
	
	public Butterer(ToastQueue dryQueue,ToastQueue buttered) {
		this.dryQueue = dryQueue;
		this.butteredQueue = buttered;
	}
	
	@Override
	public void run() {
		try {
			while(!Thread.interrupted()) {
				Toast t = dryQueue.take();
				t.buffer();
				print(t);
				butteredQueue.push(t);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		print("butterer off");
	}
	
}

class Jammer implements Runnable{
	
	private ToastQueue butteredQueue;
	private ToastQueue finishedQueue;
	
	public Jammer(ToastQueue buttered,ToastQueue finish) {
		this.butteredQueue = buttered;
		this.finishedQueue = finish;
	}
	
	@Override
	public void run() {
		try {
			while(!Thread.interrupted()) {
				Toast t = butteredQueue.take();
				t.jam();
				print(t);
				finishedQueue.push(t);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		print("Jammer off");
	}
	
}

class Eater implements Runnable{

	private ToastQueue finishQueue;
	private int count = 0;
	
	public Eater(ToastQueue finished) {
		this.finishQueue = finished;
	}
	
	@Override
	public void run() {
		try {
			while(!Thread.interrupted()) {
				Toast t = finishQueue.take();
				if(t.getID() != count++ || t.getStatus() != Toast.Status.JAMMED) {
					print(">>> Error: " + t);
					System.exit(1);
				}else {
					print("Chompl " + t);
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		print("Eater off");
	}
	
}

public class ToastOMatic {
	public static void main(String[] args) throws InterruptedException {
		ToastQueue dryQueue = new ToastQueue();
		ToastQueue butteredQueue = new ToastQueue();
		ToastQueue finishQueue = new ToastQueue();
		ExecutorService exec = Executors.newCachedThreadPool();
		exec.execute(new Toaster(dryQueue));
		exec.execute(new Butterer(dryQueue, butteredQueue));
		exec.execute(new Jammer(butteredQueue, finishQueue));
		exec.execute(new Eater(finishQueue));
		exec.execute(()->{
			print("cccccccccccc");
		});
		TimeUnit.SECONDS.sleep(5);
		exec.shutdownNow();
	}
}
